Pushing The Limits Of Windows Phone With EmailComposeTask
It’s almost 4 in the morning, and as with all great ideas, this one came to me while I was working on a completely different project. I was thinking that it is a shame that I cannot attach files to an email via EmailComposeTask
– and indeed, I am not the only one thinking about this:
Image lost since transition to new blog.
EmailComposeTask
won’t allow you to send attachments, but this doesn’t mean that you cannot send files through it. .NET Framework has these two amazing methods: Convert.ToBase64String
and Convert.FromBase64String
. The first will allow the developer to convert a byte array (byte[]
) to a Base64-encoded string, the other one will do the same operation in reverse.
Let’s say that I want to send a picture from my phone. I am going to use CameraCaptureTask
:
Microsoft.Phone.Tasks.CameraCaptureTask task = new Microsoft.Phone.Tasks.CameraCaptureTask();
task.Completed += new EventHandler(task_Completed);
task.Show();
Whenever a photo is captured, I have direct access to the resulting stream. What I can do at that point, is get the byte array from it, convert it to Base64 and set is as the body for EmailComposeTask
:
void task_Completed(object sender, Microsoft.Phone.Tasks.PhotoResult e)
{
int read = 0;
int part = 0;
byte[] buffer = new byte[22000];
while ((read = e.ChosenPhoto.Read(buffer,0,buffer.Length)) > 0)
{
Thread.Sleep(10000);
part++;
string bsfData = Convert.ToBase64String(buffer);
Debug.WriteLine(bsfData.Length);
EmailComposeTask task = new EmailComposeTask();
task.To = "[email protected]";
task.Subject = "Part " + part.ToString();
task.Body = bsfData;
task.Show();
}
}
A couple of stress points here:
- There is a content length restriction currently set to 64k (for the message body), therefore I have to split the entire captured byte array in chunks that are ready to be sent out. If ignored, an exception is thrown.
- This ultimately creates a multi-part email (read: 22 parts for a 2 megapixel photo).
- The
Thread.Sleep(10000)
creates a lag of 10 seconds betweenEmailComposeTask
invocations, because there is no completion notifier event handler for this specific task type. The user has to quickly hit send in this case. - Without a sleeping thread, I get an error.
Once all parts are sent out, on the receiving end a simple console application like this will perform the Base64-to-content conversion:
using System;
using System.IO;
namespace AttachFileReader
{
class Program
{
static void Main(string[] args)
{
string customParameter = args[0];
string inputPath = args[1];
string outputPath = args[2];
switch (customParameter)
{
case "c":
{
if (!string.IsNullOrWhiteSpace(inputPath))
{
if (!string.IsNullOrWhiteSpace(outputPath))
{
try
{
using (MemoryStream stream = new MemoryStream())
{
string data = File.ReadAllText(inputPath);
string[] content = data.Split(new char[] { '=' });
foreach (string d in content)
{
string unit = d;
unit = d.Replace("=", "");
unit += "=";
Console.WriteLine(unit.Length);
if (unit.Length > 1)
{
byte[] byteData = Convert.FromBase64String(unit);
stream.Write(byteData, 0, byteData.Length);
}
}
File.WriteAllBytes(outputPath, stream.ToArray());
Console.WriteLine("Successfully saved to " + outputPath);
}
}
catch (Exception ex)
{
Console.WriteLine("Oh snap! Something went wrong. Will this message help you?");
Console.WriteLine(ex.Message);
}
}
else
{
Console.WriteLine("Missing parameter - index 1");
}
}
else
{
Console.WriteLine("Missing parameter - index 0");
}
break;
}
default:
{
Console.WriteLine("Windows Phone Attached Email Reader v.1.0\nDeveloped by Den.");
break;
}
}
}
}
}
The first argument passed to the application is c for conversion. The second argument is the path to the text file that contains the concatenated Base64 strings. This, obviously, can be automated or be done manually. The third and last argument shows the output path.
The composite string is being broken down in chunks once again, and every single one of them is decode and written to a MemoryStream
instance, that works well for byte array merging, especially in a situation where I am writing those sequentially.
The byte array obtained from MemoryStream
is later saved to a file.
NOTE: jpg is used as a sample extension. It can be any other extension as long as the correct file format is being sent out.
This is more of a for-fun observation than a viable option for sending files. You might want to consider these choices for applications that go public:
- Send data to a web service that forwards the file to an email address
- Use a cloud storage system and upload files there directly
- Implement the email transmission protocol independently (think about
System.Net.Mail
)